<template>
  <div></div>
</template>

<script setup lang="ts">
import * as Phaser from 'phaser'
import sky from '@/assets/images/game/sky.png'
import ground from '@/assets/images/game/platform.png'
import star from '@/assets/images/game/star.png'
import bomb from '@/assets/images/game/bomb.png'
import dude from '@/assets/images/game/dude.png'

let game: Phaser.Game | undefined
let platforms: Phaser.Physics.Arcade.StaticGroup | undefined
let player: Phaser.Types.Physics.Arcade.SpriteWithDynamicBody | undefined
let cursors: Phaser.Types.Input.Keyboard.CursorKeys | undefined
let stars: Phaser.Physics.Arcade.Group | undefined
let score = 0
let scoreText: Phaser.GameObjects.Text | undefined
let bombs: Phaser.Physics.Arcade.Group | undefined
let gameOver = false

const collectStar = (player: Phaser.Physics.Arcade.Sprite, star: Phaser.Physics.Arcade.Sprite) => {
  // 简单来说，星星的物理主体被禁用，其父游戏对象被设为非活动和不可见，从而将其从显示中移除。
  star.disableBody(true, true)

  score += 10
  scoreText?.setText('Score: ' + score)

  if (stars?.countActive(true) === 0) {
    stars.children.iterate((child) => {
      if (child instanceof Phaser.Physics.Arcade.Sprite) {
        child.enableBody(true, child.x, 0, true, true)
      }
      return true
    })
    const x = player.x < 400 ? Phaser.Math.Between(400, 800) : Phaser.Math.Between(0, 400)

    const bomb = bombs?.create(x, 16, 'bomb')
    if (bomb) {
      bomb.setBounce(1)
      bomb.setCollideWorldBounds(true)
      bomb.setVelocity(Phaser.Math.Between(-200, 200), 20)
    }
  }
}

const hitBomb = function (
  this: Phaser.Scene,
  player: Phaser.Physics.Arcade.Sprite,
  star: Phaser.Physics.Arcade.Sprite
) {
  this.physics.pause()

  player.setTint(0xff0000)

  player.anims.play('turn')

  gameOver = true
}

const preload = function (this: Phaser.Scene) {
  this.load.image('sky', sky)
  this.load.image('ground', ground)
  this.load.image('star', star)
  this.load.image('bomb', bomb)
  this.load.spritesheet('dude', dude, { frameWidth: 32, frameHeight: 48 })
}
const create = function (this: Phaser.Scene) {
  // 添加背景图像 sky，显示在画面中央。
  this.add.image(400, 300, 'sky')

  platforms = this.physics.add.staticGroup()
  // 我们导入了“地面”图像。它是一个简单的绿色矩形，大小为 400 x 32 像素
  // 我们使用函数将其缩放 2 倍setScale(2)。现在它的大小为 800 x 64
  // 需要调用refreshBody()，因为我们已经缩放了静态物理体，所以我们必须告诉物理世界我们所做的更改。
  platforms.create(400, 568, 'ground').setScale(2).refreshBody()
  platforms.create(600, 400, 'ground')
  platforms.create(50, 250, 'ground')
  platforms.create(750, 220, 'ground')

  player = this.physics.add.sprite(100, 450, 'dude')
  player.setBounce(0.2)
  player.setCollideWorldBounds(true)
  //   player.body.setGravityY(300)

  this.anims.create({
    key: 'left',
    frames: this.anims.generateFrameNumbers('dude', { start: 0, end: 3 }),
    frameRate: 10,
    repeat: -1
  })
  this.anims.create({
    key: 'turn',
    frames: [{ key: 'dude', frame: 4 }],
    frameRate: 20
  })
  this.anims.create({
    key: 'right',
    frames: this.anims.generateFrameNumbers('dude', { start: 5, end: 8 }),
    frameRate: 10,
    repeat: -1
  })

  // 碰撞检测：检测玩家对象和静态物理对象组里面每个静态物体的碰撞
  this.physics.add.collider(player, platforms)

  // 键盘事件
  cursors = this.input.keyboard?.createCursorKeys()

  stars = this.physics.add.group({
    key: 'star',
    // 因为它会自动创建 1 个子项，所以重复 11 次意味着我们总共会得到 12 个
    repeat: 11,
    // 用于设置 Group 创建的 12 个子项的位置。
    // 每个子项将从 x: 12、y: 0 开始放置，x 步长为 70。
    // 这意味着第一个子项将位于 12 x 0，第二个子项位于 82 x 0 处，比 70 像素远，第三个子项位于 152 x 0，依此类推。
    setXY: { x: 12, y: 0, stepX: 70 }
  })

  stars.children.iterate((child) => {
    // 反弹范围介于 0（完全不反弹）和 1（完全反弹）之间。
    // 由于星星都是在 y 0 处生成的，重力会将它们拉下，直到它们与平台或地面相撞。
    if (child instanceof Phaser.Physics.Arcade.Sprite) {
      child.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8))
    }
    return true
  })

  // 星星与平台碰撞
  this.physics.add.collider(stars, platforms)

  // 检查玩家是否与星星重叠：这告诉 Phaser 检查玩家和星星组中任何星星之间的重叠。如果找到，则将它们传递给“collectStar”函数
  this.physics.add.overlap(
    player,
    stars,
    (player, star) => {
      collectStar(player as Phaser.Physics.Arcade.Sprite, star as Phaser.Physics.Arcade.Sprite)
    },
    () => {},
    this
  )

  scoreText = this.add.text(16, 16, 'Score: 0', { fontSize: '32px', color: '#000' })

  bombs = this.physics.add.group()

  this.physics.add.collider(bombs, platforms)

  this.physics.add.collider(
    player,
    bombs,
    (player, star) => {
      hitBomb.call(
        this,
        player as Phaser.Physics.Arcade.Sprite,
        star as Phaser.Physics.Arcade.Sprite
      )
    },
    () => {},
    this
  )
}

const update = function () {
  if (cursors && player) {
    if (cursors.left.isDown) {
      player.setVelocityX(-160)

      player.anims.play('left', true)
    } else if (cursors.right.isDown) {
      player.setVelocityX(160)

      player.anims.play('right', true)
    } else {
      player.setVelocityX(0)

      player.anims.play('turn')
    }

    if (cursors.up.isDown && player.body.touching.down) {
      player.setVelocityY(-330)
    }
  }
}
onMounted(() => {
  game = new Phaser.Game({
    // 自动选择渲染模式（WebGL 或 Canvas）。
    type: Phaser.AUTO,
    width: 800, // 游戏画布宽高。
    height: 600,
    physics: {
      default: 'arcade',
      arcade: {
        gravity: { x: 0, y: 300 },
        debug: false
      }
    },
    scene: {
      preload,
      create,
      update
    }
  })
})

onUnmounted(() => {
  if (game) {
    game.destroy(true)
  }
})
</script>

<style scoped lang="scss"></style>
